package com.ts.utils;

import com.google.common.collect.Maps;
import org.apache.commons.lang3.tuple.Triple;

import java.time.Instant;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;

/**
 * 签名建造者模式
 *
 * @author Coder.JiA
 * @date 16/1/2020 10:40 AM
 **/
public class SignBuilder {

    /**
     * 时间戳(10位)
     */
    private Long time;
    /**
     * 随机串
     */
    private String nonce;
    /**
     * 签名
     */
    private String sign;


    /**
     * 参数：请求url
     */
    private String url;
    /**
     * 请求体
     */
    private Map<String, Object> body;
    /**
     * 参数：token(充当密文)
     */
    private String token;
    /**
     * 参数：签名算法类型
     */
    private HmacSignTypeEnum signTypeEnum;


    private SignBuilder() {}
    private SignBuilder(long time, String nonce, String sign) {
        this.time = time;
        this.nonce = nonce;
        this.sign = sign;
    }

    public static SignBuilder build() {
        return new SignBuilder();
    }

    public SignBuilder url(String url) {
        this.url = url;
        return this;
    }

    public SignBuilder body(Map<String, Object> body) {
        this.body = body;
        return this;
    }

    public SignBuilder token(String token) {
        this.token = token;
        return this;
    }

    public SignBuilder signType(HmacSignTypeEnum signTypeEnum) {
        this.signTypeEnum = signTypeEnum;
        return this;
    }

    /**
     * 未开启防重放攻击签名生成
     */
    public String sign() {
        try {
            sign = SignUtil.genSign(url, body, token, signTypeEnum);
        } catch (Exception e) {
            System.out.println(
                    "报错了！！！！！！！！！！"
            );
        }
        return sign;
    }

    /**
     * 开启防重放攻击签名生成
     * @return 时间戳, 随机串, 签名
     */
    public Triple<Long, String, String> pvrSign() {
        time = Instant.now().getEpochSecond();
        nonce = UUID.randomUUID().toString();
        try {
            sign = SignUtil.genSign(time, nonce, url, body, token, signTypeEnum);
        } catch (Exception e) {
            System.out.println(
                    "报错了！！！！！！！！！！"
            );
        }
        return Triple.of(time, nonce, sign);
    }

    public static void main(String[] args) throws  Exception{
        //近七天接处警
        String token = "eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiIsInVjIjoiYjlhYTA1MGU2YjBkMTU3MTk4MDc1MDc2ZDA2ZmJiNzUiLCJ0b2tlbl90eXBlIjoxfQ.eyJpc3MiOiI5TXZuS1g0dHRXNEJETnQ0TDlIbVJRMUYyRk5tVGFLeiIsImlhdCI6MTU4ODc1NDcyM30._eOJUidGyTTKZMCj48T_dvHJo4Fpkas76JSllIpSqZg";
        String url = "/360100000/jcjsjmx";

        //重点人员背景核查
//        String token = "eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiIsInVjIjoiYjlhYTA1MGU2YjBkMTU3MTk4MDc1MDc2ZDA2ZmJiNzUiLCJ0b2tlbl90eXBlIjoxfQ.eyJpc3MiOiIzY1pRbE5MeXlyNXN2amViYXdLT3lBNndZZXJsQkFUTCIsImlhdCI6MTU4NzcxNjcwNX0.0pRKEZ6vNX4fJ4OrNV0u5h5kc-xAboewmKtaOAdSj_w";
//        String url = "/360100000/zdrybjhc";

        //视频预警_布控人员预警
//        String token = PropertyUtils.getProp("bigdata_bkryyj_token");
//        String url = PropertyUtils.getProp("bigdata_bkryyj_url");

        //重点人员统计分析
//        String token = PropertyUtils.getProp("bigdata_zdrtjfx_token");
//        String url = PropertyUtils.getProp("bigdata_zdrtjfx_url");

        //重点人员预警
//        String token = PropertyUtils.getProp("bigdata_zdryyj_token");
//        String url = PropertyUtils.getProp("bigdata_zdryyj_url");
        Map<String, Object> queryParams = Maps.newHashMap();
//        queryParams.put("page_num", 1);
//        queryParams.put("page_size", 10000);
//        queryParams.put("starttime","2020-05-15 00:00:00");
//        queryParams.put("endtime","2020-05-15 23:59:59");
//        queryParams.put("bjsj","2020-05-12 18:00:00");

//        queryParams.put("zjhm","360122196608162730");
        System.out.println(genSignUrl(url, queryParams));
        SignBuilder signBuilder = SignBuilder.build()
                .url(genSignUrl(url, queryParams))
//                .body(bodyMap)
                .token(token)
                .signType(HmacSignTypeEnum.HMAC_SHA256);
        String sign = signBuilder.sign();
        System.out.println(sign);
    }

    /**
     * 测试案例
     * 签名结果是否正确比对地址: @see <a href="https://tool.oschina.net/encrypt?type=2">在线加密解密</a>
     */
    public static void main1(String[] args) {
        /**
         * 目前body参与验签仅支持content-type为application/json
         */
        /*Map<String, Object> bodyMap = Maps.newLinkedHashMap();
        bodyMap.put("tag", true);
        bodyMap.put("url", "localhost:2222");
        bodyMap.put("key_2", new String[]{"a", "b", "c"});*/

        String token = "eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiIsInVjIjoiYjlhYTA1MGU2YjBkMTU3MTk4MDc1MDc2ZDA2ZmJiNzUiLCJ0b2tlbl90eXBlIjoxfQ.eyJpc3MiOiJNaGxCaVlJTk5Qd2R6b3B6bWVwSGtjNUZvN2NRUDFEUSIsImlhdCI6MTU4NzcxNjcwOX0.oD7U0XVSflLiyDyDw4he2YqkazASzKfep7iZTwuAlAY";
        String url = "http://47.49.27.44:8000/360100000/zdryyj";
        Map<String, Object> queryParams = Maps.newHashMap();
        queryParams.put("pageNum", "2");
        queryParams.put("pageSize", "1000");

        SignBuilder signBuilder = SignBuilder.build()
                .url(genSignUrl(url, queryParams))
//                .body(bodyMap)
                .token(token)
                .signType(HmacSignTypeEnum.HMAC_SHA256);

        //api未开启防重放攻击  4bf8614a0918e48a183d442dea2e5608f44e9c6dc0d34220e7cb94758034d87b,
        String sign = signBuilder.sign();
        Map<String, Object> header = Maps.newHashMap();
        header.put("apigs_ca_sign", sign);
        System.out.println("sign:"+sign);
        // api开启了防重放攻击 1582877763, a14944d9-0c5e-4ed1-a36b-467b0f86458d, 5b732f3f249d187ff2b412c81c3f35e5c76487f813e64732c30d4cbea1a7bf87
        Triple<Long, String, String> signTriple = signBuilder.pvrSign();
        header.put("apigs_ca_time", signTriple.getLeft());
        header.put("apigs_ca_nonce", signTriple.getMiddle());
        header.put("apigs_ca_sign", signTriple.getRight());
    }

    /**
     * 将query参数拼接到url，签名使用
     *
     * @param url
     * @param queryParams
     * @return
     */
    public static String genSignUrl(String url, Map<String, Object> queryParams) {
        Iterator<String> iterator = queryParams.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            Object value = queryParams.get(key);
            if (url.contains("?")) {
                url += "&";
            } else {
                url += "?";
            }
            url += key + "=" + value;
        }
        return url;
    }

}
